<template>
    <el-upload class="uploader" :action="currentAction" :show-file-list="false" :on-change="onFileChange" :before-upload="beforeUpload" accept="image/*,video/*" :auto-upload="false" :multiple="false">
        <!-- 预览列表：图片显示缩略图，视频显示 video 标签 -->
        <template v-if="previewList.length">
            <div v-for="(item, index) in previewList" :key="index" class="preview-item">
                <template v-if="isVideo(item)">
                    <video :src="item" controls class="thumb"></video>
                </template>
                <template v-else>
                    <img :src="item" class="thumb"/>
                </template>
                <!-- 删除按钮 -->
                <el-icon class="delete-btn" @click.stop="removeItem(index)" color="#fff">
                    <CircleCloseFilled/>
                </el-icon>
            </div>
        </template>

        <el-icon v-if="canAdd" class="uploader-icon">
            <Plus/>
        </el-icon>
    </el-upload>

    <!-- 裁剪图片弹窗 -->
    <el-dialog v-model="cropperState.visible" title="裁剪图片" width="600px" append-to-body>
        <cropper
            class="cropper"
            :src="cropperState.tempImg"
            :stencil-props="{ aspectRatio }"
            ref="cropperRef"
        />
        <template #footer>
            <div class="dialog-footer">
                <el-button @click="cropperState.visible = false">取消</el-button>
                <el-button type="primary" @click="handleCrop">确认裁剪</el-button>
            </div>
        </template>
    </el-dialog>
</template>

<script setup>
import { ref, reactive, computed } from 'vue'
import axios from 'axios'
import { Cropper } from 'vue-advanced-cropper'
import 'vue-advanced-cropper/dist/style.css'

const props = defineProps({
    modelValue: { type: [Array, String], default: '' },
    uploadActionImage: { type: String, default: () => `${import.meta.env.VITE_UPLOAD_IMAGE_URL}` },
    uploadActionVideo: { type: String, default: () => `${import.meta.env.VITE_UPLOAD_VIDEO_URL}` },
    headers: { type: Object, default: () => ({}) },
    aspectRatio: { type: Number, default: 5 / 4 },
    mode: { type: String, default: 'multiple' }, // 'single' | 'multiple'
    max: { type: Number, default: 10 }
})
const emit = defineEmits(['update:modelValue', 'success', 'error'])

const cropperState = reactive({
    visible: false,
    tempImg: ''
})
const cropperRef = ref(null)

const previewList = computed(() => {
    if (!props.modelValue) return []
    if (props.mode === 'single') {
        return typeof props.modelValue === 'string' ? [props.modelValue] : []
    } else {
        return Array.isArray(props.modelValue) ? props.modelValue : []
    }
})

const canAdd = computed(() => {
    if (props.mode === 'single') return previewList.value.length < 1
    return previewList.value.length < props.max
})

/**
 * 根据文件类型动态切换上传接口
 */
const currentAction = ref(props.uploadActionImage) // 仅用于 el-upload，实际我们手动上传

function beforeUpload (file) {
    // 不直接让 el-upload 上传，返回 false
    return false
}

function isVideo (path) {
    return /\.(mp4|webm|ogg|mov)$/i.test(path)
}

/**
 * 文件选择
 */
function onFileChange (file) {
    if (!file?.raw) return
    const type = file.raw.type
    if (type.startsWith('video/')) {
        // 直接上传视频
        uploadVideo(file.raw)
    } else if (type.startsWith('image/')) {
        // 打开裁剪弹窗
        const reader = new FileReader()
        reader.onload = e => {
            cropperState.tempImg = e.target.result
            cropperState.visible = true
        }
        reader.readAsDataURL(file.raw)
    }
}

/**
 * 上传视频
 */
async function uploadVideo (videoFile) {
    const formData = new FormData()
    formData.append('file', videoFile)
    try {
        const res = await axios.post(props.uploadActionVideo, formData, {
            headers: { 'Content-Type': 'multipart/form-data', ...props.headers }
        })
        const { code, data } = res.data || {}
        if (code === 200 && data?.url) {
            pushResult(data.url)
            emit('success', data.url)
        } else {
            emit('error', res.data)
        }
    } catch (err) {
        emit('error', err)
    }
}

/**
 * 图片裁剪后上传
 */
function handleCrop () {
    const { value: cropper } = cropperRef
    if (!cropper) return
    const { canvas } = cropper.getResult() || {}
    if (!canvas) return

    canvas.toBlob(async blob => {
        if (!blob) return
        const formData = new FormData()
        formData.append('file', blob, 'crop.png')
        try {
            const res = await axios.post(props.uploadActionImage, formData, {
                headers: { 'Content-Type': 'multipart/form-data', ...props.headers }
            })
            const { code, data } = res.data || {}
            if (code === 200 && data?.url) {
                pushResult(data.url)
                emit('success', data.url)
            } else {
                emit('error', res.data)
            }
        } catch (err) {
            emit('error', err)
        } finally {
            cropperState.visible = false
        }
    })
}

/**
 * 根据模式更新数组
 */
function pushResult (url) {
    if (props.mode === 'single') {
        // 单图模式，直接传字符串
        emit('update:modelValue', url)
    } else {
        // 多图模式，传数组
        const newList = [...previewList.value, url].slice(0, props.max)
        emit('update:modelValue', newList)
    }
}

// 删除图片/视频
function removeItem (index) {
    const newList = [...previewList.value]
    newList.splice(index, 1)
    emit('update:modelValue', newList)
}
</script>

<style scoped>
.uploader {
    cursor: pointer;
    display: flex;
    flex-wrap: wrap;
}

.uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 150px;
    height: 120px;
    text-align: center;
    line-height: 120px;
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
}

.preview-item {
    position: relative;
    margin-right: 8px;
    display: inline-block;
    border: 1px dashed transparent;
    width: 150px;
    height: 120px;
    &:hover {
        border: 1px dashed #d9d9d9;
    }
    .thumb {
        width: 150px;
        height: 120px;
        object-fit: cover;
        background: #333;
    }
    .delete-btn {
        position: absolute;
        top: 6px;
        right: 6px;
        z-index: 10;
        font-size: 20px;
        &:hover {
            color: var(--el-color-danger);
        }
    }
}


</style>
